﻿using System;
using System.Collections.Generic;
using GeneticAlgorithms.Genomes;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace GeneticAlgorithms.Tests.Utils
{
    static class ExtraAssert
    {
        public static void MethodFails(
            Action method, 
            Action<Exception> exceptionChecker,
            string message)
        {
            bool threw = false;
            try
            {
                method();
            }
            catch (Exception exc)
            {
                exceptionChecker(exc);
                threw = true;
            }

            Assert.IsTrue(threw, message);
        }

        public static void MethodFails(
            Action method,
            Action<Exception> exceptionChecker)
        {
            MethodFails(method, exceptionChecker, "Method failed to throw the expected exception.");
        }

        public static void MethodThrowsArgumentException(Action method, string paramName)
        {
            MethodThrowsArgumentException(method, paramName, typeof(ArgumentException));
        }

        public static void MethodThrowsArgumentException(
            Action method, 
            string paramName,
            Type exceptionType)
        {
            MethodFails(
                method,
                e =>
                {
                    Assert.IsInstanceOfType(e, exceptionType);
                    Assert.AreEqual(((ArgumentException)e).ParamName, paramName);
                });
        }

        public static void MethodThrowsArgumentNullException(Action method, string paramName)
        {
            MethodThrowsArgumentException(method, paramName, typeof(ArgumentNullException));
        }

        public static void MethodThrowsArgumentOutOfRangeException(Action method, string paramName)
        {
            MethodThrowsArgumentException(method, paramName, typeof(ArgumentOutOfRangeException));
        }

        public static void GenomesMatch<TGene>(
            IGenome<TGene> expected, 
            IGenome<TGene> actual)
        {
            Assert.AreEqual(expected.Length, actual.Length, "Expected and actual genomes must have the same length.");
            for (int i = 0; i < expected.Length; ++i)
            {
                Assert.AreEqual(expected[i], actual[i], "Genes at position {0} do not match", i);
            }
        }

        public static void GenomeCollectionsMatch<TGenome, TGene>(
            IList<TGenome> expected,
            IList<TGenome> actual)
            where TGenome : IGenome<TGene>
        {
            Assert.AreEqual(expected.Count, actual.Count, "Expected and actual genomes collections must have the same count.");
            for (int i = 0; i < expected.Count; ++i)
            {
                ExtraAssert.GenomesMatch<TGene>(expected[i], actual[i]);
            }
        }
    }
}
